# 测试pr
import pygame
import sys
import random

# 全局定义
SCREEN_X = 1200
SCREEN_Y = 1000
WALL_NUMBER = 0
LIFE_NUMBER = 1
FPS = 15


# 蛇类
# 点以25为单位
class Snake(object):
    # 初始化各种需要的属性 [开始时默认向右/身体块x5]
    def __init__(self):
        self.dirction = pygame.K_RIGHT
        self.body = []
        for x in range(5):
            self.addnode()

    # 无论何时 都在前端增加蛇块
    def addnode(self):
        left, top = (0, 100)
        if self.body:
            left, top = (self.body[0].left, self.body[0].top)
        node = pygame.Rect(left, top, 25, 25)
        if self.dirction == pygame.K_LEFT:
            node.left -= 25
        elif self.dirction == pygame.K_RIGHT:
            node.left += 25
        elif self.dirction == pygame.K_UP:
            node.top -= 25
        elif self.dirction == pygame.K_DOWN:
            node.top += 25
        self.body.insert(0, node)

    # 删除最后一个块
    def delnode(self):
        self.body.pop()

    def reduce_by_half(self):
        length = len(self.body)
        if length > 2:
            for i in range(length // 2):
                self.delnode()
        else:
            pass

    # 死亡判断
    def isdead(self, score):
        global LIFE_NUMBER
        # 撞墙
        if self.body[0].x not in range(-1, SCREEN_X) or self.body[0].y not in range(SCREEN_Y - 25 * WALL_NUMBER):
            if LIFE_NUMBER in [0, 1]:
                LIFE_NUMBER = 0
                return True
            else:
                score -= 100
                LIFE_NUMBER -= 1
                self.body = self.body[::-1]
                # 判断反弹方向
                if self.body[0].x == self.body[1].x:
                    if self.body[0].y > self.body[1].y:
                        self.dirction = pygame.K_DOWN
                    else:
                        self.dirction = pygame.K_UP
                if self.body[0].y == self.body[1].y:
                    if self.body[0].x > self.body[1].x:
                        self.dirction = pygame.K_RIGHT
                    else:
                        self.dirction = pygame.K_LEFT
                else:
                    pass
                return False
        # 撞自己
        if self.body[0] in self.body[1:]:
            if LIFE_NUMBER in [0, 1]:
                LIFE_NUMBER = 0
                return True
            else:
                LIFE_NUMBER -= 1
                score -= 100
                return False

        if len(self.body) == 0:
            return True
        return False

    # 移动！
    def move(self):
        self.addnode()
        self.delnode()

    # 改变方向 但是左右、上下不能被逆向改变
    def changedirection(self, curkey):
        LR = [pygame.K_LEFT, pygame.K_RIGHT]
        UD = [pygame.K_UP, pygame.K_DOWN]
        if curkey in LR + UD:
            if (curkey in LR) and (self.dirction in LR):
                return
            if (curkey in UD) and (self.dirction in UD):
                return
            self.dirction = curkey


class Snake_Enemy(object):

    def __init__(self):
        self.dirction = 'down'
        self.body = []
        for x in range(5):
            self.addnode()

    # 无论何时 都在前端增加蛇块
    def addnode(self):
        left, top = (800, 0)
        if self.body:
            left, top = (self.body[0].left, self.body[0].top)
        node = pygame.Rect(left, top, 25, 25)
        if self.dirction == 'left':
            node.left -= 25
        elif self.dirction == 'right':
            node.left += 25
        elif self.dirction == 'up':
            node.top -= 25
        elif self.dirction == 'down':
            node.top += 25
        self.body.insert(0, node)

    # 删除最后一个块
    def delnode(self):
        self.body.pop()

    # 移动！
    def move(self):
        self.addnode()
        self.delnode()

    def action(self, score):
        if self.body[0].x not in range(-1, SCREEN_X) or self.body[0].y not in range(SCREEN_Y - 25 * WALL_NUMBER):
            score -= 100
            self.body = self.body[::-1]
            # 判断反弹方向
            if self.body[0].x == self.body[1].x:
                if self.body[0].y > self.body[1].y:
                    self.dirction = 'down'
                else:
                    self.dirction = 'up'
            if self.body[0].y == self.body[1].y:
                if self.body[0].x > self.body[1].x:
                    self.dirction = 'right'
                else:
                    self.dirction = 'left'
            else:
                pass
            return False

    # 改变方向 但是左右、上下不能被逆向改变
    def changenemydirection(self):
        LR = ['left', 'right']
        UD = ['up', 'down']
        curkey = random.choice(LR + UD)
        if curkey in LR + UD:
            if (curkey in LR) and (self.dirction in LR):
                return
            if (curkey in UD) and (self.dirction in UD):
                return
            self.dirction = curkey

    def isdead(self):
        if len(self.body) == 0:
            self.dirction = 'down'
            for i in range(5):
                self.addnode()


# 食物类
# 方法： 放置/移除
# 点以25为单位
class Food:
    def __init__(self):
        self.rect = pygame.Rect(-25, 0, 25, 25)
        self.symbol = 0

    def remove(self):
        self.rect.x = -25

    # 普通食物投递
    def set(self, number, snake):
        if self.rect.x == -25:
            allpos_x = []
            allpos_y = []
            # 不靠墙太近 25 ~ SCREEN_X-25 之间
            for pos_x in range(25, SCREEN_X - 25, 25):
                allpos_x.append(pos_x)
            for pos_y in range(25, SCREEN_Y - 25 * number, 25):
                allpos_y.append(pos_y)
            # 避免在蛇身体里生成食物
            for item in snake:
                if item.x in allpos_x:
                    allpos_x.remove(item.x)
                if item.y in allpos_y:
                    allpos_y.remove(item.y)
            self.rect.left = random.choice(allpos_x)
            self.rect.top = random.choice(allpos_y)
            # print(self.rect)

    def food_effect(self):
        self.symbol = random.randint(0, 50)


class Wall:
    def __init__(self):
        self.rect = pygame.Rect(-SCREEN_X, SCREEN_Y, SCREEN_X, 25)

    def remove(self):
        self.rect.x = -SCREEN_X

    def add_wall(self, number):
        if self.rect.x == -SCREEN_X:
            self.rect.left = 0
            self.rect.top = SCREEN_Y - 25 * number
            self.rect.height = 25 * number


def show_text(screen, pos, text, color, font_bold=False, font_size=60, font_italic=False):
    # 获取系统字体，并设置文字大小
    cur_font = pygame.font.SysFont("宋体", font_size)
    # 设置是否加粗属性
    cur_font.set_bold(font_bold)
    # 设置是否斜体属性
    cur_font.set_italic(font_italic)
    # 设置文字内容
    text_fmt = cur_font.render(text, 1, color)
    # 绘制文字
    screen.blit(text_fmt, pos)


def main():
    pygame.init()
    screen_size = (SCREEN_X, SCREEN_Y)
    screen = pygame.display.set_mode(screen_size)
    pygame.display.set_caption('Snake')

    sound1, sound2 = True, True
    pygame.mixer.music.load('background_music.mp3')
    pygame.mixer.music.play(loops=99)
    clock = pygame.time.Clock()
    scores = 0
    isdead = False

    # 蛇/食物
    snake = Snake()
    food = Food()
    wall = Wall()
    snake_enemy = Snake_Enemy()

    global WALL_NUMBER, LIFE_NUMBER, FPS
    pygame.time.set_timer(1, 10000)
    pygame.time.set_timer(2, 2000)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            if event.type == pygame.KEYDOWN:
                snake.changedirection(event.key)
                # 死后按space重新
                if event.key == pygame.K_SPACE and isdead:
                    WALL_NUMBER = 0
                    LIFE_NUMBER = 1
                    return main()
                if event.key == pygame.K_ESCAPE and isdead:
                    sys.exit()
            if event.type == 1:
                WALL_NUMBER += 1
            if event.type == 2:
                snake_enemy.changenemydirection()

        screen.fill((0, 0, 0))
        # 画蛇身 / 每一步+1分
        if not isdead:
            scores += 1
            snake.move()
            snake_enemy.move()
        for index, rect in enumerate(snake.body):
            if index == 0:
                pygame.draw.rect(screen, (218, 165, 32), rect, 0)
            else:
                pygame.draw.rect(screen, (20, 220, 39), rect, 0)

        for index, rect in enumerate(snake_enemy.body):
            if index == 0:
                pygame.draw.rect(screen, (218, 165, 32), rect, 0)
            else:
                pygame.draw.rect(screen, (255, 20, 147), rect, 0)

        # 显示死亡文字
        isdead = snake.isdead(scores)
        snake_enemy.action(scores)
        if isdead:
            if sound2:
                sound2 = False
                pygame.mixer.init()
                pygame.mixer.music.load('Dead.mp3')
                if pygame.mixer.music.get_busy() != 1:
                    pygame.mixer.music.play()
            show_text(screen, (100, 200), 'YOU DEAD!', (227, 29, 18), False, 100)
            show_text(screen, (150, 260), 'press space to try again...', (0, 0, 22), False, 30)

        # 食物处理 / 吃到+50分
        # 当食物rect与蛇头重合,吃掉 -> Snake增加一个Node
        # symbol为0时加100分,长度变为一半，symbol为1时加一条命，加150分，symbol为其他数字时，加50分
        if food.rect == snake.body[0]:
            food.food_effect()
            if WALL_NUMBER >= 1:
                WALL_NUMBER -= 1
            food.remove()
            if food.symbol == 0:
                scores += 100
                snake.reduce_by_half()
            elif food.symbol == 1:
                scores += 150
                LIFE_NUMBER += 1
                snake.addnode()
            else:
                scores += 150
                snake.addnode()
        # 敌人蛇把食物吃掉
        if food.rect == snake_enemy.body[0]:
            food.food_effect()
            WALL_NUMBER += 1
            food.remove()
            if food.symbol == 0:
                scores -= 100
                for i in range(5):
                    snake_enemy.addnode()
            elif food.symbol == 1:
                scores -= 150
                LIFE_NUMBER += 1
                snake_enemy.addnode()
            else:
                scores -= 50
                snake_enemy.addnode()
        # 敌人蛇把蛇吃掉
        if snake_enemy.body[0] in snake.body:
            snake.delnode()
            snake_enemy.addnode()
            scores -= 200

        if snake.body[0] in snake_enemy.body:
            snake.addnode()
            snake_enemy.delnode()
            scores += 200

        # 墙体生成
        wall.remove()
        wall.add_wall(WALL_NUMBER)
        pygame.draw.rect(screen, (136, 0, 21), wall.rect, 0)
        # 墙体把食物吃掉 -25分
        if food.rect.y == wall.rect.y:
            scores -= 25
            food.remove()
            food.set(WALL_NUMBER, snake.body)

        # 食物投递

        food.set(WALL_NUMBER, snake.body + snake_enemy.body)
        pygame.draw.rect(screen, (136, 0, 21), food.rect, 0)

        # 显示分数文字
        show_text(screen, (50, 400), 'Life: ' + str(LIFE_NUMBER), (223, 223, 223))
        show_text(screen, (50, 450), 'Scores: ' + str(scores), (223, 223, 223))

        pygame.display.update()
        clock.tick(FPS)


if __name__ == '__main__':
    main()
